package thread;

/**
 * 同步块：
 * 语法：
 * synchronized(同步监视器对象){
 *       需要多个线程同步执行的代码片段(多线程会产生并发安全问题的代码)
 * }
 *
 * 有效的缩小同步范围是可以在保证并发安全的前提下尽可能提高并发效率
 *
 * */
public class SyncDemo2 {
    public static void main(String[] args) {
        Shop shop=new Shop();
//        Shop shop1=new Shop();
//        Shop shop2=new Shop();
        Thread t1=new Thread("王克晶"){
            public void run(){
                shop.buy(); //this指向
//                shop1.buy(); //this指向
            }
        };
        Thread t2=new Thread("范传奇"){
            public void run(){
                shop.buy();  //this指向
//                shop2.buy();  //this指向
            }
        };
        t1.start();
        t2.start();

    }
}
class Shop{
//    public synchronized void buy(){
    public  void buy(){
        try {
            Thread t=Thread.currentThread();//获取运行buy方法的线程

            System.out.println(t.getName()+":正在挑衣服....");
            Thread.sleep(5000);

            /*
            同步块可以更精准的控制需要同步执行的代码片段
            但是使用同步块时要指定同步监视器对象，同步监视器对象要同时具备以下条件：
            1：必须是引用类型实例
            2：多个需要同步执行该代码片段的线程看到的必须是同一个对象

            合适的锁对象,应当是在多个线程出现"抢"的时候发挥左右，否则不发发挥作用
            例如：两个线程分别执行两个Shop实例的buy方法（相当于两个人去不同的商店）时，那么这两个
            线程就不发生"抢"的现象,此时下面的同步块就不应当要求线程排队执行代码.
            如果同步监视器对象选取了字符串字面量(字符串字面量在任何情况下都是同一个对象),那么在
             这样的情况下也要求多个线程排队执行显然是不合适的.
             */
            /*
            synchronized不是公平项，当一个线程进入后，如果后续有5个线程陆续执行到这里开始排队
            时，当进入的线程出了同步块后，并不是后五个中先排队的线程先进入，而是后五个线程谁
            先拿到时间片谁先进入执行
            如果想实现公平项，可以使用JVC(java.util.concurrent)
            java.util.concurrent.locks.ReentranLock 可重入锁可以实现公平锁机制
             */
            synchronized (this) {
                //无效的锁对象，因为多个线程看到的不是同一个对象
//                synchronized (new Object()){ //同步块没有起到作用！
//                synchronized ("hello"){ //有效但不合适
                System.out.println(t.getName() + ":正在试衣服....");
                Thread.sleep(5000);
            }

            System.out.println(t.getName()+"：结账离开！");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}
